﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows.Data;

using QLTT.Commands;
using System.Windows.Input;
using QLTT.Models;
using System.Windows;

namespace QLTT.ViewModels
{
    public class MainViewModel : WorkspaceViewModel
    {
        #region Fields
        ObservableCollection<WorkspaceViewModel> _workspaces;
        bool _isAdministrator;
        bool _isAuthorized;
        
        DelegateCommand _allTeacherCommand;
        DelegateCommand _teacherCommand;
        DelegateCommand _classCommand;
        DelegateCommand _allClassCommand;
        DelegateCommand _allRoomCommand;
        DelegateCommand _roomCommand;
        DelegateCommand _levelCommand;
        DelegateCommand _allLevelCommand;
        DelegateCommand _studentCommand;
        DelegateCommand _allStudentCommand;
        DelegateCommand _classTimeCommand;
        DelegateCommand _allClassTimeCommand;
        DelegateCommand _absenceCommand;
        DelegateCommand _allAbsenceCommand;
        DelegateCommand _classMarkCommand;
        DelegateCommand _loginCommand;
        DelegateCommand _logoutCommand;
        DelegateCommand _userCommand;
        DelegateCommand _allUserCommand;
        DelegateCommand _closeAllCommand;
        DelegateCommand _classScheduleCommand;

        DelegateCommand _exitCommand;
        #endregion // Fields

        #region Properties
        public bool IsAdministrator
        {
            get { return _isAdministrator; }
            set
            {
                if (_isAdministrator == value)
                    return;
                _isAdministrator = value;
                base.OnPropertyChanged("IsAdministrator");
            }
        }
        public bool IsAuthorized
        {
            get { return _isAuthorized; }
            set
            {
                if (_isAuthorized == value)
                    return;
                _isAuthorized = value;
                base.OnPropertyChanged("IsAuthorized");
            }
        }
        #endregion
        #region Constructor
        public MainViewModel()
        {
            LoginViewModel loginViewModel = new LoginViewModel();
            this.Workspaces.Add(loginViewModel);
            this.SetActiveWorkspace(loginViewModel);

            //UserViewModel userViewModel = new UserViewModel(new icanDataContext());
            //this.Workspaces.Add(userViewModel);
            //this.SetActiveWorkspace(userViewModel);
            
        }
        #endregion // Constructor
        #region Commands
        #region Common helpers
        private bool CanExcute()
        {
            return this.IsAuthorized;
        }
        private bool CanExcuteAdmin()
        {
            return this.IsAdministrator;
        }
        #endregion
        #region Add AllTeacherView Command
        public ICommand AllTeacherCommand
        {
            get 
            {
                if (_allTeacherCommand == null)
                    _allTeacherCommand = new DelegateCommand(AddAllTeacherView, CanExcute);
                return _allTeacherCommand;
            }
        }
        public void AddAllTeacherView()
        {
            icanDataContext dataContext = new icanDataContext();
            AllTeacherViewModel allTeacherViewModel = new AllTeacherViewModel(dataContext, true);
            this.Workspaces.Add(allTeacherViewModel);
            this.SetActiveWorkspace(allTeacherViewModel);
        }
        #endregion
        #region Add TeacherView Command
        public ICommand TeacherCommand
        {
            get
            {
                if (_teacherCommand == null)
                    _teacherCommand = new DelegateCommand(AddTeacherView, CanExcute);
                return _teacherCommand;
            }
        }
        public void AddTeacherView()
        {
            icanDataContext dataContext = new icanDataContext();
            TeacherViewModel teacherViewModel = new TeacherViewModel(dataContext);
            this.Workspaces.Add(teacherViewModel);
            this.SetActiveWorkspace(teacherViewModel);
        }
        #endregion
        #region Add ClassView Command
        public ICommand ClassCommand
        {
            get
            {
                if (_classCommand == null)
                    _classCommand = new DelegateCommand(AddClassView, CanExcute);
                return _classCommand;
            }
        }
        public void AddClassView()
        {
            icanDataContext dataContext = new icanDataContext();
            ClassViewModel classViewModel = new ClassViewModel(dataContext);
            this.Workspaces.Add(classViewModel);
            this.SetActiveWorkspace(classViewModel);
        }
        #endregion
        #region Add AllClassView Command
        public ICommand AllClassCommand
        {
            get
            {
                if (_allClassCommand == null)
                    _allClassCommand = new DelegateCommand(AddAllClassView, CanExcute);
                return _allClassCommand;
            }
        }
        public void AddAllClassView()
        {
            icanDataContext dataContext = new icanDataContext();
            AllClassViewModel allClassViewModel = new AllClassViewModel(dataContext, true);
            this.Workspaces.Add(allClassViewModel);
            this.SetActiveWorkspace(allClassViewModel);
        }
        #endregion
        #region Add RoomView Command
        public ICommand RoomCommand
        {
            get
            {
                if (_roomCommand == null)
                    _roomCommand = new DelegateCommand(AddRoomView, CanExcute);
                return _roomCommand;
            }
        }
        public void AddRoomView()
        {
            icanDataContext dataContext = new icanDataContext();
            RoomViewModel roomViewModel = new RoomViewModel(dataContext);
            this.Workspaces.Add(roomViewModel);
            this.SetActiveWorkspace(roomViewModel);
        }
        #endregion
        #region Add AllRoomView Command
        public ICommand AllRoomCommand
        {
            get
            {
                if (_allRoomCommand == null)
                    _allRoomCommand = new DelegateCommand(AddAllRoomView, CanExcute);
                return _allRoomCommand;
            }
        }
        public void AddAllRoomView()
        {
            icanDataContext dataContext = new icanDataContext(); 
            AllRoomViewModel allRoomViewModel = new AllRoomViewModel(dataContext, true);
            this.Workspaces.Add(allRoomViewModel);
            this.SetActiveWorkspace(allRoomViewModel);
        }
        #endregion
        #region Add LevelView Command
        public ICommand LevelCommand
        {
            get
            {
                if (_levelCommand == null)
                    _levelCommand = new DelegateCommand(AddLevelView, CanExcute);
                return _levelCommand;
            }
        }
        public void AddLevelView()
        {
            icanDataContext dataContext = new icanDataContext();
            LevelViewModel levelViewModel = new LevelViewModel(dataContext);
            this.Workspaces.Add(levelViewModel);
            this.SetActiveWorkspace(levelViewModel);
        }
        #endregion
        #region Add AllLevelView Command
        public ICommand AllLevelCommand
        {
            get
            {
                if (_allLevelCommand == null)
                    _allLevelCommand = new DelegateCommand(AddAllLevelView, CanExcute);
                return _allLevelCommand;
            }
        }
        public void AddAllLevelView()
        {
            icanDataContext dataContext = new icanDataContext();
            AllLevelViewModel allLevelViewModel = new AllLevelViewModel(dataContext, true);
            this.Workspaces.Add(allLevelViewModel);
            this.SetActiveWorkspace(allLevelViewModel);
        }
        #endregion
        #region Add StudentView Command
        public ICommand StudentCommand
        {
            get
            {
                if (_studentCommand == null)
                    _studentCommand = new DelegateCommand(AddStudentView, CanExcute);
                return _studentCommand;
            }
        }
        public void AddStudentView()
        {
            icanDataContext dataContext = new icanDataContext();
            StudentViewModel studentViewModel = new StudentViewModel(dataContext);
            this.Workspaces.Add(studentViewModel);
            this.SetActiveWorkspace(studentViewModel);
        }
        #endregion
        #region Add AllStudentView Command
        public ICommand AllStudentCommand
        {
            get
            {
                if (_allStudentCommand == null)
                    _allStudentCommand = new DelegateCommand(AddAllStudentView, CanExcute);
                return _allStudentCommand;
            }
        }
        public void AddAllStudentView()
        {
            icanDataContext dataContext = new icanDataContext(); 
            AllStudentViewModel allStudentViewModel = new AllStudentViewModel(dataContext, true);
            this.Workspaces.Add(allStudentViewModel);
            this.SetActiveWorkspace(allStudentViewModel);
        }
        #endregion
        #region Add AllClassTimeView Command
        public ICommand AllClassTimeCommand
        {
            get
            {
                if (_allClassTimeCommand == null)
                    _allClassTimeCommand = new DelegateCommand(AddAllClassTimeView, CanExcute);
                return _allClassTimeCommand;
            }
        }
        public void AddAllClassTimeView()
        {
            icanDataContext dataContext = new icanDataContext();
            AllClassTimeViewModel allClassTimeViewModel = new AllClassTimeViewModel(dataContext, true);
            this.Workspaces.Add(allClassTimeViewModel);
            this.SetActiveWorkspace(allClassTimeViewModel);
        }
        #endregion
        #region Add ClassTimeView Command
        public ICommand ClassTimeCommand
        {
            get
            {
                if (_classTimeCommand == null)
                    _classTimeCommand = new DelegateCommand(AddClassTimeView, CanExcute);
                return _classTimeCommand;
            }
        }
        public void AddClassTimeView()
        {
            icanDataContext dataContext = new icanDataContext();
            ClassTimeViewModel classTimeViewModel = new ClassTimeViewModel(dataContext);
            this.Workspaces.Add(classTimeViewModel);
            this.SetActiveWorkspace(classTimeViewModel);
        }
        #endregion
        #region Add ClassMarkView Command
        public ICommand ClassMarkCommand
        {
            get
            {
                if (_classMarkCommand == null)
                    _classMarkCommand = new DelegateCommand(AddClassMarkView, CanExcute);
                return _classMarkCommand;
            }
        }
        public void AddClassMarkView()
        {
            icanDataContext dataContext = new icanDataContext(); 
            ClassMarkViewModel classTimeViewModel = new ClassMarkViewModel(dataContext);
            this.Workspaces.Add(classTimeViewModel);
            this.SetActiveWorkspace(classTimeViewModel);
        }
        #endregion
        #region Add AbsenceView Command
        public ICommand AbsenceCommand
        {
            get
            {
                if (_absenceCommand == null)
                    _absenceCommand = new DelegateCommand(ClassAbsenceView, CanExcute);
                return _absenceCommand;
            }
        }
        public void ClassAbsenceView()
        {
            icanDataContext dataContext = new icanDataContext();
            ClassAbsenceViewModel absenceViewModel = new ClassAbsenceViewModel(dataContext);
            this.Workspaces.Add(absenceViewModel);
            this.SetActiveWorkspace(absenceViewModel);
        }
        #endregion
        #region Add AllAbsenceView Command
        public ICommand AllAbsenceCommand
        {
            get
            {
                if (_allAbsenceCommand == null)
                    _allAbsenceCommand = new DelegateCommand(AddAllAbsenceView, CanExcute);
                return _allAbsenceCommand;
            }
        }
        public void AddAllAbsenceView()
        {
            icanDataContext dataContext = new icanDataContext();
            AllAbsenceViewModel allAbsenceViewModel = new AllAbsenceViewModel(dataContext, true);
            this.Workspaces.Add(allAbsenceViewModel);
            this.SetActiveWorkspace(allAbsenceViewModel);
        }
        #endregion
        #region CloseAll Command
        public ICommand CloseAllCommand
        {
            get
            {
                if (_closeAllCommand == null)
                    _closeAllCommand = new DelegateCommand(CloseAll);
                return _closeAllCommand;
            }
        }
        public void CloseAll()
        {
            for (int i = this.Workspaces.Count-1; i >= 0; i--)
            {
                this.Workspaces.RemoveAt(i);
            }
        }
        #endregion
        #region Login Command
        public ICommand LoginCommand
        {
            get
            {
                if (_loginCommand == null)
                    _loginCommand = new DelegateCommand(Login, CanLogin);
                return _loginCommand;
            }
        }
        public void Login()
        {
            LoginViewModel loginViewModel = new LoginViewModel();
            this.Workspaces.Add(loginViewModel);
            this.SetActiveWorkspace(loginViewModel);
        }
        public bool CanLogin()
        {
            return !this.IsAuthorized;
        }
        #endregion
        #region Logout Command
        public ICommand LogoutCommand
        {
            get
            {
                if (_logoutCommand == null)
                    _logoutCommand = new DelegateCommand(Logout, CanExcute);
                return _logoutCommand;
            }
        }
        public void Logout()
        {
            CloseAll();
            ViewModelBase.CurrentUser = null;
            this.IsAdministrator = false;
            this.IsAuthorized = false;
            Login();
        }
        #endregion
        #region Add UserView Command
        public ICommand UserCommand
        {
            get
            {
                if (_userCommand == null)
                    _userCommand = new DelegateCommand(UserView, CanExcute);
                return _userCommand;
            }
        }
        public void UserView()
        {
            icanDataContext dataContext = new icanDataContext();
            User user = dataContext.Users.FirstOrDefault(u => u.ID == ViewModelBase.CurrentUser.ID);
            ViewModelBase.CurrentUser = user;
            UserViewModel userViewModel = new UserViewModel(dataContext, user);
            this.Workspaces.Add(userViewModel);
            this.SetActiveWorkspace(userViewModel);
        }
        #endregion
        #region Add AllUserView Command
        public ICommand AllUserCommand
        {
            get
            {
                if (_allUserCommand == null)
                    _allUserCommand = new DelegateCommand(AddAllUserView, CanExcuteAdmin);
                return _allUserCommand;
            }
        }
        public void AddAllUserView()
        {
            icanDataContext dataContext = new icanDataContext();
            AllUserViewModel allUserViewModel = new AllUserViewModel(dataContext, true);
            this.Workspaces.Add(allUserViewModel);
            this.SetActiveWorkspace(allUserViewModel);
        }
        #endregion
        #region Add ClassScheduleView Command
        public ICommand ClassScheduleCommand
        {
            get
            {
                if (_classScheduleCommand == null)
                    _classScheduleCommand = new DelegateCommand(AddClassScheduleView, CanExcute);
                return _classScheduleCommand;
            }
        }
        public void AddClassScheduleView()
        {
            icanDataContext dataContext = new icanDataContext();
            ClassScheduleViewModel ClassScheduleViewModel = new ClassScheduleViewModel(dataContext, false);
            this.Workspaces.Add(ClassScheduleViewModel);
            this.SetActiveWorkspace(ClassScheduleViewModel);
        }
        #endregion
        #region Exit Command
        public ICommand ExitCommand
        {
            get
            {
                if (_exitCommand == null)
                    _exitCommand = new DelegateCommand(Exit);
                return _exitCommand;
            }
        }
        public void Exit()
        {
            Application.Current.Shutdown();
        }
        #endregion
        #endregion
        #region Workspaces

        /// <summary>
        /// Returns the collection of available workspaces to display.
        /// A 'workspace' is a ViewModel that can request to be closed.
        /// </summary>
        public ObservableCollection<WorkspaceViewModel> Workspaces
        {
            get
            {
                if (_workspaces == null)
                {
                    _workspaces = new ObservableCollection<WorkspaceViewModel>();
                    _workspaces.CollectionChanged += this.OnWorkspacesChanged;
                }
                return _workspaces;
            }
        }

        void OnWorkspacesChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null && e.NewItems.Count != 0)
                foreach (WorkspaceViewModel workspace in e.NewItems)
                    workspace.RequestClose += this.OnWorkspaceRequestClose;

            if (e.OldItems != null && e.OldItems.Count != 0)
                foreach (WorkspaceViewModel workspace in e.OldItems)
                    workspace.RequestClose -= this.OnWorkspaceRequestClose;
        }

        void OnWorkspaceRequestClose(object sender, EventArgs e)
        {
            WorkspaceViewModel workspace = sender as WorkspaceViewModel;
            RemoveChildWorkspace(workspace);
        }

        #endregion // Workspaces
        #region Private Helpers
        void SetActiveWorkspace(WorkspaceViewModel workspace)
        {
            Debug.Assert(this.Workspaces.Contains(workspace));

            ICollectionView collectionView = CollectionViewSource.GetDefaultView(this.Workspaces);
            
            if (collectionView != null)
                collectionView.MoveCurrentTo(workspace);
        }
        [MediatorLib.MediatorMessageSink(Messages.WorkspaceAdd, ParameterType = typeof(WorkspaceViewModel))]
        void AddChildWorkspace(WorkspaceViewModel childWs)
        {
            ICollectionView collectionView = CollectionViewSource.GetDefaultView(this.Workspaces);
            if (collectionView == null)
                return;
            WorkspaceViewModel currentWs = (WorkspaceViewModel)collectionView.CurrentItem;
            int index = this.Workspaces.IndexOf(currentWs);
            childWs.ParentWorkspace = currentWs;
            if (index > -1)
                this.Workspaces[index] = childWs;
        }
        [MediatorLib.MediatorMessageSink(Messages.WorkspaceRemove, ParameterType = typeof(WorkspaceViewModel))]
        void RemoveChildWorkspace(WorkspaceViewModel childWs)
        {
            WorkspaceViewModel parentWs = childWs.ParentWorkspace;

            if (parentWs == null)
                this.Workspaces.Remove(childWs);
            else
            {
                int index = this.Workspaces.IndexOf(childWs);
                if (index > -1)
                    this.Workspaces[index] = parentWs;
            }
            childWs.Dispose();
        }
        [MediatorLib.MediatorMessageSink(Messages.UserChanged, ParameterType = typeof(User))]
        void ChangeUser(User user)
        {
            if (user == null)
            {
                this.IsAdministrator = false;
                this.IsAuthorized = false;
            }
            else
            {
                this.IsAdministrator = (UserRole)user.Role == UserRole.Administrator;
                this.IsAuthorized = true;
            }
        }
        #endregion // Private Helpers
    }
}
